package junior.util.date;

import junior.util.ArrayUtils;
import junior.util.exception.ExceptionUtils;
import org.springframework.util.StringUtils;

import java.sql.Time;
import java.sql.Timestamp;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 日期工具类
 *
 * @author WuBo
 * @CreateDate 2012-8-13 下午12:21:25
 */
public class DateUtils {
    /**
     * 根据pattern得到SafeSimpleDateFormat
     *
     * @param pattern
     * @return
     * @author WuBo
     * @CreateDate 2012-8-13 下午12:36:19
     */
    public static DateFormat getDateFormat(String pattern) {
        return DateFormat.ofPattern(pattern);
    }
    
    /*---------------------------------------------------------*/
    
    /**
     * 根据指定的DateFormat转换日期为字符串
     * @param date
     * @param dateFormat
     * @return
     */
    public static String dateToStr(Date date, DateFormat dateFormat) {
        return dateFormat.format(date);
    }
    
    /**
     * 根据指定的DateFormat转换字符串为日期
     * @param str
     * @param dateFormat
     * @return
     */
    public static Date strToDate(String str, DateFormat dateFormat) {
        return dateFormat.parse(str);
    }
    
    /**
     * 转换java.sql.Date为字符串，只包含日期部分，DateFormat固定为yyyy-MM-dd
     * @param date
     * @return
     */
    public static String sqlDateToStr(java.sql.Date date) {
        return DateFormat.DATE_DASH.format(date);
    }
    
    /**
     * 转换字符串为java.sql.Date, DateFormat固定为yyyy-MM-dd
     * @param str
     * @return
     */
    public static java.sql.Date strToSqlDate(String str) {
        try {
            Date date = DateFormat.DATE_DASH.getFormatter().parse(str);
            return new java.sql.Date(date.getTime());
        } catch (ParseException e) {
            throw ExceptionUtils.wrap2Runtime(e);
        }
    }
    
    /**
     * 转换Time为字符串，包含时间部分，DateFormat固定为HH:mm:ss
     * @param time
     * @return
     */
    public static String sqlTimeToStr(Time time) {
        return DateFormat.TIME_COLON.format(time);
    }
    
    /**
     * 转换字符串为java.sql.Time, DateFormat固定为HH:mm:ss
     * @param str
     * @return
     */
    public static java.sql.Time strToSqlTime(String str) {
        try {
            Date date = DateFormat.TIME_COLON.getFormatter().parse(str);
            return new java.sql.Time(date.getTime());
        } catch (ParseException e) {
            throw ExceptionUtils.wrap2Runtime(e);
        }
    }
    
    /**
     * 转换Timestamp为字符串，包含日期和时间部分，DateFormat固定为yyyy-MM-dd HH:mm:ss.SSS
     * @param timestamp
     * @return
     */
    public static String sqlTimestampToStr(Timestamp timestamp) {
        return DateFormat.DATE_DASH_TIME_NANO_COLON.format(timestamp);
    }
    
    /**
     * 转换字符串为java.sql.Timestamp, DateFormat固定为yyyy-MM-dd HH:mm:ss.SSS
     * @param str
     * @return
     */
    public static java.sql.Timestamp strToSqlTimestamp(String str) {
        try {
            Date date = DateFormat.DATE_DASH_TIME_NANO_COLON.getFormatter().parse(str);
            return new java.sql.Timestamp(date.getTime());
        } catch (ParseException e) {
            throw ExceptionUtils.wrap2Runtime(e);
        }
    }
    
    /*---------------------------------------------------------*/
    
    /**
     * 转换日期为固定的格式字符串: yyyy-MM-dd HH:mm:ss
     *
     * @param date
     * @return 格式化的日期字符串
     */
    public static String date2Str(Date date) {
        return dateToStr(date, DateFormat.DATE_DASH_TIME_COLON);
    }
    
    /**
     * 转换日期为自定义的格式字符串
     *
     * @param date
     * @param pattern
     * @return 格式化的日期字符串
     */
    public static String date2Str(Date date, String pattern) {
        if (null == date) {
            return null;
        }
        return getDateFormat(pattern).format(date);
    }
    
    /**
     * 智能化的将字符转换成日期格式
     *
     * @param date
     * @return
     * @throws ParseException
     */
    public static Date str2Date(String date) throws ParseException {
        if (!StringUtils.hasText(date)) {
            return null;
        }
        return DateFormat.tryParse(date);
    }
    
    /**
     * 尝试自动转换日期，这个方法会根据传入的字符串自动查找匹配的DateFormat来转换
     * @param date
     * @param pattern
     * @return
     * @throws ParseException
     */
    public static Date str2Date(String date, String pattern) throws ParseException {
        if (!StringUtils.hasText(date)) {
            return null;
        }
        
        return getDateFormat(pattern).parse(date);
    }
    
    /**
     * 尝试自动转换日期，这个方法会根据传入的字符串自动查找匹配的DateFormat来转换
     * @param date
     * @return
     * @throws ParseException
     */
    public static Date parse2Date(String date) throws ParseException {
        if (!StringUtils.hasText(date)) {
            return null;
        }
        if (date.matches("\\d+")) return new Date(Long.parseLong(date));
        
        return DateFormat.tryParse(date);
    }
    
    /**
     * 尝试自动转换日期，这个方法会根据传入的字符串自动转换为日期或时间（规则是是否包含空格和：）
     * @param dateTime
     * @return
     * @throws ParseException
     */
    public static Date parse2DateTime(String dateTime) throws ParseException {
        if (dateTime.matches("\\d+")) return new Date(Long.parseLong(dateTime));
        
        String[] spt = dateTime.split("[ ]+");
        String d = spt[0];
        String pattern = "";
        if (d.indexOf(":") != -1) {
            pattern += getTimePattern(d);
        } else {
            pattern = getDatePattern(d);
        }
        
        if (spt.length > 1) {
            pattern += " " + getTimePattern(spt[1]);
        }
        
        return getDateFormat(pattern).parse(dateTime);
    }
    
    /**
     * 转换时间，根据长度自动识别时分秒部分
     * @param time
     * @return
     * @throws ParseException
     */
    public static Date parse2Time(String time) throws ParseException {
        return getDateFormat(getTimePattern(time)).parse(time);
    }
    
    private static String getTimePattern(String time) {
        int l = time.split(":").length;
        if (l > 2) {
            return "HH:mm:ss";
        } else if (l == 2) {
            return "HH:mm";
        }
        return "HH";
    }
    
    private static String getDatePattern(String date) {
        String split = "-";
        if (date.indexOf("/") != -1) split = "/";
        
        String[] spt = date.split(split);
        List<String> arr = new ArrayList<String>(3);
        boolean month = false, day = false;
        for (String t : spt) {
            if (t.length() == 4) {
                arr.add("yyyy");
            } else {
                int n = Integer.parseInt(t);
                int l = t.length();
                if (n > 31) {
                    arr.add("yy");
                } else if (n > 12) {
                    if (!day) {
                        arr.add("dd");
                        day = true;
                    } else {
                        arr.add("yy");
                    }
                } else {
                    if (month) {
                        if (l == 2) arr.add("dd");
                        else arr.add("d");
                    } else {
                        if (l == 2) arr.add("MM");
                        else arr.add("M");
                        month = true;
                    }
                }
            }
        }
        return ArrayUtils.join(arr.toArray(), split);
    }
    
    /**
     * 得到最原始的日期，对于Java来说是从1970-01-01开始的
     *
     * @return
     */
    public static Date getOriginal() {
        return new Date(0);
    }
    
    /**
     * 得到一天的开始时间
     *
     * @param date
     * @return
     */
    public static Date getDayBegin(Date date) {
        if (date == null) return null;
        
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }
    
    /**
     * 得到一天的结束时间
     *
     * @param date
     * @return
     */
    public static Date getDayEnd(Date date) {
        if (date == null) return null;
        
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND, 999);
        return cal.getTime();
    }
    
    public static Date max(Date... dates) {
        Date maxDate = null;
        for (Date d : dates) {
            if (maxDate == null) {
                maxDate = d;
                continue;
            }
            if (d != null) {
                if (d.compareTo(maxDate) > 0) {
                    maxDate = d;
                }
            }
        }
        return maxDate;
    }
    
    public static Date min(boolean nullIsMin, Date... dates) {
        Date minDate = null;
        boolean hasNull = false;
        for (Date d : dates) {
            if (minDate == null) {
                minDate = d;
                continue;
            }
            if (d != null) {
                if (d.compareTo(minDate) < 0) {
                    minDate = d;
                }
            } else {
                hasNull = true;
            }
        }
        if (nullIsMin) {
            return hasNull ? null : minDate;
        }
        return minDate;
    }
    
}
